package com.xbrother.lucene.store;

import org.apache.lucene.store.IndexInput;

import java.io.IOException;

/**
 * IndexInput 和 IndexOutput 是用于读取和写入索引数据的类，需要将它们与数据库操作绑定。
 *
 * @author huangchangjin
 * @date 2025/5/13 19:33
 */
public class DatabaseIndexInput extends IndexInput {

    private final DatabaseIndexStore databaseIndexStore;
    private final String fileName;
    private byte[] data;
    private long position;

    public DatabaseIndexInput(String fileName, DatabaseIndexStore databaseIndexStore) throws IOException {
        super("DatabaseIndexInput(file=" + fileName + ")");
        this.fileName = fileName;
        this.databaseIndexStore = databaseIndexStore;
        this.data = databaseIndexStore.readFile(fileName);
        this.position = 0;
    }

    @Override
    public void close() throws IOException {
        // 无需额外操作
        data = null;
    }

    @Override
    public long getFilePointer() {
        return position;
    }

    @Override
    public void seek(long pos) throws IOException {
        if (pos < 0 || pos >= data.length) {
            throw new IOException("Seek position out of bounds: " + pos);
        }
        this.position = pos;
    }

    @Override
    public long length() {
        return data.length;
    }

    @Override
    public IndexInput slice(String sliceDescription, long offset, long length) throws IOException {
        if (offset < 0 || length < 0 || offset + length > data.length) {
            throw new IOException("Slice out of bounds");
        }
        return new SlicedDatabaseIndexInput(sliceDescription, this, offset, length);
    }

    @Override
    public byte readByte() throws IOException {
        if (position >= data.length) {
            throw new IOException("Read past EOF");
        }
        return data[(int) position++];
    }

    @Override
    public void readBytes(byte[] b, int offset, int len) throws IOException {
        if (position + len > data.length) {
            throw new IOException("Read past EOF");
        }
        System.arraycopy(data, (int) position, b, offset, len);
        position += len;
    }

    // 内部类：支持切片操作
    private static class SlicedDatabaseIndexInput extends IndexInput {
        private final DatabaseIndexInput parent;
        private final long sliceOffset;
        private final long sliceLength;
        private long slicePosition;

        public SlicedDatabaseIndexInput(String sliceDescription, DatabaseIndexInput parent,
                                        long offset, long length) {
            super("SlicedDatabaseIndexInput(" + sliceDescription + ")");
            this.parent = parent;
            this.sliceOffset = offset;
            this.sliceLength = length;
            this.slicePosition = 0;
        }

        @Override
        public void close() {
        }

        @Override
        public long getFilePointer() {
            return slicePosition;
        }

        @Override
        public void seek(long pos) {
            if (pos < 0 || pos >= sliceLength) {
                throw new IllegalArgumentException("Seek out of slice bounds");
            }
            slicePosition = pos;
        }

        @Override
        public long length() {
            return sliceLength;
        }

        @Override
        public byte readByte() throws IOException {
            if (slicePosition >= sliceLength) {
                throw new IOException("Read past EOF in slice");
            }
            parent.seek(sliceOffset + slicePosition++);
            return parent.readByte();
        }

        @Override
        public void readBytes(byte[] b, int offset, int len) throws IOException {
            if (slicePosition + len > sliceLength) {
                throw new IOException("Read past EOF in slice");
            }
            parent.seek(sliceOffset + slicePosition);
            parent.readBytes(b, offset, len);
            slicePosition += len;
        }

        @Override
        public IndexInput slice(String sliceDescription, long offset, long length) throws IOException {
            if (offset < 0 || length < 0 || offset + length > sliceLength) {
                throw new IOException("Slice out of bounds");
            }
            return new SlicedDatabaseIndexInput(sliceDescription, parent, sliceOffset + offset, length);
        }
    }
}
